/************************************************************************
* fork.c
* Copyright (C) Lisa Milne 2013 <lisa@ltmnet.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
************************************************************************/

#include "dish.h"
#include "path.h"
#include "env.h"

#include <sys/wait.h>

/* fork the command */
int forkit(cmd_t *cmd)
{
	char* c;

	if (builtin_check(cmd->cmd)) {
		cmd->estate = builtin_exec(cmd->argc,cmd->argv,cmd->env,cmd->stdin.fd,cmd->stdout.fd,cmd->stderr.fd);
		env_set_int("?",cmd->estate,1);
		if (cmd->estate == -1) {
			ERROR("error: Builtin command not implemented.\n");
			return 1;
		}
		if (cmd->estate == -2)
			return -1;
		return 0;
	}

	c = epath_which(cmd->cmd);
	if (!c) {
		ERROR(TARGET);
		ERROR(": ");
		ERROR(cmd->cmd);
		ERROR(": command not found.\n");
		return 1;
	}

	if (!(cmd->flags&CMD_EXEC)) {
		cmd->pid = fork();
		if (cmd->pid < 0) {
			return 1;
		}else if (cmd->pid > 0) {
			if (cmd->stdin.fd != STDIN_FILENO)
				close(cmd->stdin.fd);
			if (cmd->stdout.fd != STDOUT_FILENO)
				close(cmd->stdout.fd);
			if (cmd->stderr.fd != STDERR_FILENO)
				close(cmd->stderr.fd);
			if ((cmd->flags&CMD_IMMEDIATE) || (cmd->flags&CMD_BACKGROUND))
				return 0;
			waitpid(cmd->pid,&cmd->estate,0);
			env_set_int("?",cmd->estate,1);
			if ((cmd->flags&CMD_CONDITIONAL)) {
				if (cmd->estate != 0 && !(cmd->flags&CMD_INVERSE))
					return 1;
				if (cmd->estate == 0 && (cmd->flags&CMD_INVERSE))
					return 1;
			}

			return 0;
		}
	}

	if (cmd->stdin.fd != STDIN_FILENO) {
		close(STDIN_FILENO);
		dup2(cmd->stdin.fd,STDIN_FILENO);
	}

	if (cmd->stdout.fd != STDOUT_FILENO) {
		close(STDOUT_FILENO);
		dup2(cmd->stdout.fd,STDOUT_FILENO);
	}

	if (cmd->stderr.fd != STDERR_FILENO) {
		close(STDERR_FILENO);
		dup2(cmd->stderr.fd,STDERR_FILENO);
	}

	execve(c,cmd->argv,cmd->env);

	exit(1);
	return 0;
}
